#pragma once

#include "thread.h"
#include "event.h"

namespace mswin {

///the thread that repeats its doit() method upon request
class repeat_thread : public thread
{
public:
	repeat_thread();
	void repeat(); ///< wakes the thread, if multiple repeat() are called while doit() is not finished they act as one repeat()
protected:
	void start(); ///< last child should call StartThread() in its ctor
	void terminate(); ///< last child should call TerminateThread() in its dtor
	virtual void doit() = 0; ///< this method will be called from work thread's run()
private:
	virtual void run(); ///< do not call it, only overload
	using thread::wait_finish;
private:
	mswin::event new_order_; ///< set in main thread when something has to be done, reset in work thread when the work is done
	volatile bool terminating_; ///< signals (in destructor) to work thread to exit
};

//inlines

inline repeat_thread::repeat_thread() : new_order_(false)
	{ }

inline void repeat_thread::repeat()
	{ new_order_.set(); }

inline void repeat_thread::start()
{ 
	terminating_ = false;
	resume();
}

inline void repeat_thread::terminate()
{
	terminating_ = true;
	new_order_.set();
	wait_finish();
}

inline void repeat_thread::run()
{
	for (;;) {
		new_order_.wait();
		new_order_.reset();
		if (terminating_)
			break;
		doit();
	}
}

} //namespace mswin
